package com.ttbj.yitongpay.service.impl;

import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.ttbj.core.util.BeanUtil;
import com.ttbj.yitongpay.bean.ActiveScanQRCodeData;
import com.ttbj.yitongpay.bean.HandlePayData;
import com.ttbj.yitongpay.bean.PassiveScanQRCodeData;
import com.ttbj.yitongpay.service.ScanQRCodeService;
import com.ttbj.yitongpay.util.HttpClient;
import com.ttbj.yitongpay.util.MD5;
import com.ttbj.yitongpay.util.PropertiesUtil;

@Service("scanQRCodeService")
public class ScanQRCodeServiceImpl implements ScanQRCodeService{
	
	private static Logger logger = LoggerFactory.getLogger(ScanQRCodeServiceImpl.class);

	
	@Override
	public Map<String, String> activeScanQrCode(Object object) throws Exception{
		ActiveScanQRCodeData sCodeData = new ActiveScanQRCodeData();	//这个地方不能赋值null，否则报错
		if (object instanceof ActiveScanQRCodeData) {	//如果obj属于ScanQRCodeData类型，则直接强转
			logger.info("obj对象属于ScanQRCodeData类型");
			sCodeData = (ActiveScanQRCodeData) object;
		}else {	//如果obj不属于ScanQRCodeData类型，则复制属性，排除Null值
			logger.info("obj对象不属于ScanQRCodeData类型，进行复制属性，排除Null值");
			BeanUtil.copyProperties(sCodeData, object);
		}
		//如果必填的属性为""或null，则抛出异常终止
		if (StringUtils.isEmpty(sCodeData.getMerOrderNum()) || StringUtils.isEmpty(sCodeData.getTranAmt()) 
				|| StringUtils.isEmpty(sCodeData.getSysTraceNum())) {
			throw new Exception("参数不能为空或null");
		}
		//设置交易时间：YYYYMMDDHHMMSS
		String tranDateTime = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
		//获取版本号
		String version = PropertiesUtil.getInstance().getValue("version");
		//获取交易代码
		String transCode = PropertiesUtil.getInstance().getValue("transCode");
		//获取商户编号
		String merchantId = PropertiesUtil.getInstance().getValue("merchantId");
		//获取业务代码
		String bussId = PropertiesUtil.getInstance().getValue("bussId");
		//获取货币代码
		String currencyType = PropertiesUtil.getInstance().getValue("currencyType");
		//获取商户返回页面
		String merURL = PropertiesUtil.getInstance().getValue("merURL");
		//获取回调商户地址
//		String backURL = PropertiesUtil.getInstance().getValue("backURL");
		//支付方式代码
		String bankId = PropertiesUtil.getInstance().getValue("bankId");
		//获取入口类型
		String entryType = PropertiesUtil.getInstance().getValue("entryType");
		//获取密钥
		String datakey = PropertiesUtil.getInstance().getValue("datakey");
		//获取易通金服支付URL
		String URL = PropertiesUtil.getInstance().getValue("bankSelect_url");
		//如果有值的话，就会返回html代码，所以设置为""
		String orderInfo = "";
		//拼接签名前的字符串
		String txnString = version + "|" + transCode + "|" + merchantId + "|" + sCodeData.getMerOrderNum() + "|" 
				+ bussId + "|" + sCodeData.getTranAmt() + "|" + sCodeData.getSysTraceNum() + "|" 
				+ tranDateTime + "|"+ currencyType + "|" + merURL + "|" + sCodeData.getBackURL() + "|" + orderInfo 
				+ "|" + sCodeData.getUserId();
		System.out.println("签名前字符串：" + txnString + datakey);
		//使用md5进行签名
		String signValue = MD5.getInstance().getMD5ofStr(txnString + datakey);
		
		Map<String, String> mapData = new HashMap<>();
		mapData.put("version", version);
		mapData.put("transCode", transCode);
		mapData.put("merchantId", merchantId);
		mapData.put("merOrderNum", sCodeData.getMerOrderNum());
		mapData.put("bussId", bussId);
		mapData.put("tranAmt", sCodeData.getTranAmt());
		mapData.put("sysTraceNum", sCodeData.getSysTraceNum());
		mapData.put("tranDateTime", tranDateTime);
		mapData.put("currencyType", currencyType);
		mapData.put("merURL", merURL);
		mapData.put("backURL", sCodeData.getBackURL());
		mapData.put("orderInfo", orderInfo);
		mapData.put("userId", sCodeData.getUserId());
		mapData.put("userIp", sCodeData.getUserIp());
		mapData.put("bankId", bankId);
		mapData.put("stlmId", sCodeData.getStlmId());
		mapData.put("entryType", entryType);
		mapData.put("attach", sCodeData.getAttach());
		mapData.put("signValue", signValue);
		mapData.put("channel", sCodeData.getChannel());
		mapData.put("authCode", sCodeData.getAuthCode());
		mapData.put("activeTime", sCodeData.getActiveTime());
		mapData.put("payPage", sCodeData.getPayPage());
		
		//HTTP连接，发送数据并获取返回的数据
		String result = new HttpClient(URL, 6000, 6000).send(mapData, "UTF-8");
		mapData.clear();
		//把返回的字符串转成Map
		mapData = transStringToMap(result, "&", "=");
		return mapData;
	}
	
	
	@Override
	public Map<String, Object> activeCallBackFunction(Object object) throws Exception {
		HandlePayData d = new HandlePayData();
		if (object instanceof HandlePayData) {
			logger.info("object属于 HandlePayData 类型 ");
			d = (HandlePayData) object;
		}else {
			logger.info("object不属于 HandlePayData 类型 ");
			BeanUtil.copyProperties(d, object);
		}
		//获取密钥
		String datakey = PropertiesUtil.getInstance().getValue("datakey");
		//验签前拼接字符串
		String txnString = d.getTransCode() + "|" + d.getMerchantId() + "|" + d.getRespCode() + "|" 
				+ d.getSysTraceNum() + "|" + d.getMerOrderNum() + "|" + d.getOrderId() + "|" + d.getBussId() + "|" 
				+ d.getTranAmt() + "|" + d.getOrderAmt() + "|" + d.getBankFeeAmt() + "|" + d.getIntegralAmt() + "|" 
				+ d.getVaAmt() + "|" + d.getBankAmt() + "|" + d.getBankId() + "|" + d.getIntegralSeq() + "|" + d.getVaSeq() 
				+ "|" + d.getBankSeq()+ "|" + d.getTranDateTime() + "|" + d.getPayMentTime() + "|" 
				+  d.getSettleDate() + "|" + d.getCurrencyType() + "|" + d.getOrderInfo() + "|" + d.getUserId();
		//MD5加密
		String md5SignStr = MD5.getInstance().getMD5ofStr(txnString + datakey);
		logger.info("验证签名加密 --> {}, 返回的签名-->{}", md5SignStr, d.getSignValue());
		//对比结果，如果结果不相同，说明报文被人篡改，丢弃
		if (!md5SignStr.equals(d.getSignValue())) {
			throw new Exception("报文被人篡改，请立即停止支付！");
		}
		return getValueMap(d);
	}
	
	
	@Override
	public Map<String, String> transactionQuery(String merOrderNum, String tranDate, int scanQRType) throws Exception{
		String merchantId = null;
		String dataKey = null;
		//如果是主扫（微信/支付宝）获取商户号和dataKey
		if (scanQRType == 1) {
			merchantId = PropertiesUtil.getInstance().getValue("merchantId");
			dataKey = PropertiesUtil.getInstance().getValue("datakey");
		}else if(scanQRType == 2) {	//如果是被扫（微信小程序）获取商户号和dataKey
			merchantId = PropertiesUtil.getInstance().getValue("wxSP_merchantId");
			dataKey = PropertiesUtil.getInstance().getValue("wxSP_datakey");
		}
		//进行字符串截取：yyyyMMdd
		tranDate = StringUtils.substring(tranDate, 0, 8);
		String txnString = merchantId + "|" + merOrderNum + "|" + tranDate;
		//签名
		String signValue = MD5.getInstance().getMD5ofStr(txnString + dataKey);
		//获取查询的url
		String queryURL = PropertiesUtil.getInstance().getValue("query_url");
		Map<String, String> mapData = new HashMap<>();
		mapData.put("merchantId", merchantId);
		mapData.put("merOrderNum", merOrderNum);
		mapData.put("tranDate", tranDate);
		mapData.put("signValue", signValue);
		//HTTP连接，发送数据并获取返回的数据
		String result = new HttpClient(queryURL, 6000, 6000).send(mapData, "UTF-8");
		mapData.clear();
		if (StringUtils.contains(result, "&")) {
			mapData = transStringToMap(result, "&", "=");
		}else {
			mapData.put("respCode", "none");
		}
		return mapData;
	}
	
	
	@Override
	public Map<String, String> passiveScanQrCode(Object object) throws Exception {
		PassiveScanQRCodeData data = new PassiveScanQRCodeData();
		if (object instanceof PassiveScanQRCodeData) {
			logger.info("object属于 PassiveScanQRCodeData 类型 ");
			data = (PassiveScanQRCodeData) object;
		}else {
			logger.info("object不属于 PassiveScanQRCodeData 类型 ");
			BeanUtil.copyProperties(data, object);
		}
		//设置交易时间：YYYYMMDDHHMMSS
		String tranDateTime = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
		//获取版本号
		String version = PropertiesUtil.getInstance().getValue("version");
		//获取交易代码
		String transCode = PropertiesUtil.getInstance().getValue("transCode");
		//获取商户编号
		String merchantId = PropertiesUtil.getInstance().getValue("wxSP_merchantId");
		//获取业务代码
		String bussId = PropertiesUtil.getInstance().getValue("wxSP_bussId");
		//获取货币代码
		String currencyType = PropertiesUtil.getInstance().getValue("currencyType");
		//获取商户返回页面
		String merURL = PropertiesUtil.getInstance().getValue("merURL");
		//获取回调商户地址
//		String backURL = PropertiesUtil.getInstance().getValue("wxSP_backURL");
		//支付方式代码
		String bankId = PropertiesUtil.getInstance().getValue("wxSP_bankId");
		//获取入口类型
		String entryType = PropertiesUtil.getInstance().getValue("entryType");
		//获取密钥
		String datakey = PropertiesUtil.getInstance().getValue("wxSP_datakey");
		//获取易通金服支付URL
		String URL = PropertiesUtil.getInstance().getValue("wxSP_bankSelect_url");
		//获取app_id
		String sub_appid = PropertiesUtil.getInstance().getValue("sub_appid");
		//拼接签名前的字符串
		String txnString = version + "|" + transCode + "|" + merchantId + "|" + data.getMerOrderNum() + "|" 
				+ bussId + "|" + data.getTranAmt() + "|" + data.getSysTraceNum() + "|" 
				+ tranDateTime + "|"+ currencyType + "|" + merURL + "|" + data.getBackURL() + "|" + data.getOrderInfo() 
				+ "|" + data.getUserId() + "|" + data.getAuthCode();
		//生成签名
		String signValue = MD5.getInstance().getMD5ofStr(txnString + datakey);
		logger.info("微信小程序-生成的signValue是{}", signValue);
		Map<String, String> mapData = new HashMap<>();
		mapData.put("version", version);
		mapData.put("transCode", transCode);
		mapData.put("merchantId", merchantId);
		mapData.put("merOrderNum", data.getMerOrderNum());
		mapData.put("bussId", bussId);
		mapData.put("tranAmt", data.getTranAmt());
		mapData.put("sysTraceNum", data.getSysTraceNum());
		mapData.put("tranDateTime", tranDateTime);
		mapData.put("currencyType", currencyType);
		mapData.put("merURL", merURL);
		mapData.put("backURL", data.getBackURL());
		mapData.put("orderInfo", data.getOrderInfo());
		mapData.put("userId", data.getUserId());
		mapData.put("userIp", data.getUserIp());
		mapData.put("bankId", bankId);
		mapData.put("stlmId", data.getStlmId());
		mapData.put("entryType", entryType);
		mapData.put("attach", data.getAttach());
		mapData.put("signValue", signValue);
		mapData.put("channel", data.getChannel());
		mapData.put("sub_appid", sub_appid);
		mapData.put("sub_openid", data.getSub_openid());
		mapData.put("authCode", data.getAuthCode());
		mapData.put("activeTime", data.getActiveTime());
		
		//HTTP连接，发送数据并获取返回的数据
		System.out.println(mapData);
		System.out.println("url--"+URL);
		String result = new HttpClient(URL, 6000, 6000).send(mapData, "UTF-8");
		mapData.clear();
		mapData = transStringToMap(result, "&", "=");
		return mapData;
	}
	
	
	@Override
	public Map<String, Object> passiveCallBackFunction(Object object) throws Exception {
		PassiveScanQRCodeData d = new PassiveScanQRCodeData();
		if (object instanceof PassiveScanQRCodeData) {
			logger.info("object属于 PassiveScanQRCodeData 类型 ");
			d = (PassiveScanQRCodeData) object;
		}else {
			logger.info("object不属于 PassiveScanQRCodeData 类型 ");
			BeanUtil.copyProperties(d, object);
		}
		//获取密钥
		String datakey = PropertiesUtil.getInstance().getValue("wxSP_datakey");
		//验签前拼接字符串
		String txnString = d.getTransCode() + "|" + d.getMerchantId() + "|" + d.getRespCode() + "|" 
				+ d.getSysTraceNum() + "|" + d.getMerOrderNum() + "|" + d.getOrderId() + "|" + d.getBussId() + "|" 
				+ d.getTranAmt() + "|" + d.getOrderAmt() + "|" + d.getBankFeeAmt() + "|" + d.getIntegralAmt() + "|" 
				+ d.getVaAmt() + "|" + d.getBankAmt() + "|" + d.getBankId() + "|" + d.getIntegralSeq() + "|" + d.getVaSeq() 
				+ "|" + d.getBankSeq()+ "|" + d.getTranDateTime() + "|" + d.getPayMentTime() + "|" 
				+  d.getSettleDate() + "|" + d.getCurrencyType() + "|" + d.getOrderInfo() + "|" + d.getUserId();
		logger.info("md5验签前字符串：{}", txnString + datakey);
		//MD5加密
		String md5SignStr = MD5.getInstance().getMD5ofStr(txnString + datakey);
		logger.info("验证签名加密 --> {}, 返回的签名-->{}", md5SignStr, d.getSignValue());
		//对比结果，如果结果不相同，说明报文被人篡改，丢弃
		if (!md5SignStr.equals(d.getSignValue())) {
			throw new Exception("报文被人篡改，请立即停止支付！");
		}
		return getValueMap(d);
	}
	
    
    /**
     * 使用 Map按key进行排序得到key=value的字符串
     * @param mapString
     * @param separator K-V与K-V之间的拼接字符串  & 或者|...
     * @param pairSeparator K与V之间的拼接字符串 = 或者其他...
     * @return
     */
    public static Map<String, String> transStringToMap(String mapString, String separator, String pairSeparator) {
    	Map<String, String> map = new HashMap<String, String>();
    	String[] fSplit = mapString.split(separator);
    	for (int i = 0; i < fSplit.length; i++) {
	          if (fSplit[i]==null||fSplit[i].length()==0) {
	              continue;
	          }
	          String[] sSplit = fSplit[i].split(pairSeparator);
	          String value = fSplit[i].substring(fSplit[i].indexOf('=') + 1, fSplit[i].length());
	          map.put(sSplit[0], value);
         }
         return map;
     }
    
    
    /**
     * 实体类转为MAP
     * @return
     */
    public static Map<String, Object> getValueMap(Object obj) {
        Map<String, Object> map = new HashMap<String, Object>();
        // 获取f对象对应类中的所有属性域
        Field[] fields = obj.getClass().getDeclaredFields();
        for (int i = 0, len = fields.length; i < len; i++) {
            String varName = fields[i].getName();
            try {
                // 获取原来的访问控制权限
                boolean accessFlag = fields[i].isAccessible();
                // 修改访问控制权限
                fields[i].setAccessible(true);
                // 获取在对象f中属性fields[i]对应的对象中的变量
                Object o = fields[i].get(obj);
                if (o != null)
                    map.put(varName, o.toString());
                // 恢复访问控制权限
                fields[i].setAccessible(accessFlag);
            } catch (IllegalArgumentException ex) {
                ex.printStackTrace();
            } catch (IllegalAccessException ex) {
                ex.printStackTrace();
            }
        }
        return map;
    }

}
